home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / cfengine-1.5.3 / src / tidy.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-06-07  |  13.5 KB  |  594 lines

  1. /* cfengine for GNU
  2.  
  3.         Copyright (C) 1995
  4.         Free Software Foundation, Inc.
  5.  
  6.    This file is part of GNU cfengine - written and maintained 
  7.    by Mark Burgess, Dept of Computing and Engineering, Oslo College,
  8.    Dept. of Theoretical physics, University of Oslo
  9.  
  10.    This program is free software; you can redistribute it and/or modify it
  11.    under the terms of the GNU General Public License as published by the
  12.    Free Software Foundation; either version 2, or (at your option) any
  13.    later version.
  14.  
  15.    This program is distributed in the hope that it will be useful,
  16.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.    GNU General Public License for more details.
  19.  
  20.   You should have received a copy of the GNU General Public License
  21.   along with this program; if not, write to the Free Software
  22.   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  23.  
  24. */
  25.  
  26.  
  27. #include "cf.defs.h"
  28. #include "cf.extern.h"
  29.  
  30.  
  31. /*********************************************************************/
  32. /*                                                                   */
  33. /* Tidy object                                                       */
  34. /*                                                                   */
  35. /*********************************************************************/
  36.  
  37. RecursiveHomeTidy(name,level,tp)
  38.  
  39. char *name;
  40. int level;
  41. struct Tidy *tp;
  42.  
  43. { struct stat statbuf;
  44.   DIR *dirh;
  45.   struct dirent *dirp;
  46.   char pcwd[bufsize];
  47.   time_t ticks;
  48.  
  49. if (strlen(name) == 0)
  50.    {
  51.    name = "/";
  52.    }
  53.  
  54. Debug2("HomeTidy: Opening %s\n",name);
  55.  
  56. if ((dirh = opendir(name)) == NULL)
  57.    {
  58.    sprintf(OUTPUT,"Can't open directory %s\n",name);
  59.    CfLog(cferror,OUTPUT,"");
  60.    return;
  61.    }
  62.  
  63. if (level == 2)
  64.    {
  65.    strcpy(VLOGFILE,name);
  66.    strcat(VLOGFILE,"/.cfengine.rm");
  67.  
  68.    /* Unlink here to avoid an exploit which could be used to overwrite a system
  69.       file with root privileges. */
  70.    
  71.    if (unlink(VLOGFILE) == -1)
  72.       {
  73.       sprintf(OUTPUT,"Pre-existing object %s could not be removed\n",VLOGFILE);
  74.       CfLog(cfverbose,OUTPUT,"unlink");
  75.       }
  76.    
  77.    if ((VLOGFP = fopen(VLOGFILE,"w")) == NULL)         /* log deleted files for each user */
  78.       {
  79.       sprintf(OUTPUT,"Couldn't open a file %s\n",VLOGFILE);
  80.       CfLog(cferror,OUTPUT,"fopen");
  81.       VLOGFP = stderr;
  82.       }
  83.    else
  84.       {
  85.       ticks = time((time_t *)NULL);
  86.       fprintf(VLOGFP,"This file is generated by cfengine %s\n",VERSION);
  87.       fprintf(VLOGFP,"It contains a log of the files which have been tidied.\n");
  88.       fprintf(VLOGFP,"The time of writing is %s\n",ctime(&ticks));
  89.       fprintf(VLOGFP,"If you have any questions about this, send them to %s.\n",VSYSADM);
  90.       fprintf(VLOGFP,"-(Start transcript)---------------\n");
  91.       }
  92.    }
  93.  
  94. for (dirp = readdir(dirh); dirp != NULL; dirp = readdir(dirh))
  95.    {
  96.    if (!SensibleFile(dirp->d_name,name,NULL))
  97.       {
  98.       continue;
  99.       }
  100.  
  101.    if (IgnoreFile(name,dirp->d_name,NULL))
  102.       {
  103.       continue;
  104.       }
  105.  
  106.    strcpy(pcwd,name);                                 /* Assemble pathname */
  107.    AddSlash(pcwd);
  108.  
  109.    if (BufferOverflow(pcwd,dirp->d_name))
  110.       {
  111.       return;
  112.       }
  113.  
  114.    strcat(pcwd,dirp->d_name);
  115.  
  116.    if (TRAVLINKS)
  117.       {
  118.       if (stat(pcwd,&statbuf) == -1)
  119.          {
  120.          sprintf(OUTPUT,"Can't stat %s\n",pcwd);
  121.      CfLog(cferror,OUTPUT,"stat");
  122.          continue;
  123.          }
  124.       }
  125.    else
  126.       {
  127.       if (lstat(pcwd,&statbuf) == -1)
  128.          {
  129.          if (DEBUG || D2 || VERBOSE)
  130.             {
  131.             sprintf(OUTPUT,"Can't stat %s\n",pcwd);
  132.         CfLog(cferror,OUTPUT,"lstat");
  133.             if (readlink(pcwd,VBUFF,bufsize) != -1)
  134.                {
  135.                sprintf(OUTPUT,"File is link to -> %s\n",VBUFF);
  136.            CfLog(cferror,OUTPUT,"");
  137.                }
  138.             }
  139.          continue;
  140.          }
  141.       }
  142.  
  143.  
  144.    if (S_ISDIR(statbuf.st_mode))
  145.       {
  146.       if (IsMountedFileSystem(&statbuf,pcwd,1))
  147.          {
  148.          continue;
  149.          }
  150.       else
  151.          {
  152.          RecursiveHomeTidy(pcwd,level+1,tp);
  153.          }
  154.       }
  155.    else
  156.       {
  157.       TidyHomeFile(pcwd,dirp->d_name,&statbuf);
  158.       }
  159.    }
  160.  
  161. if (level == 2)
  162.    {
  163.    fclose(VLOGFP);
  164.    chmod(VLOGFILE,DEFAULTMODE);
  165.    }
  166.  
  167. closedir(dirh);
  168. }
  169.  
  170.  
  171. /*********************************************************************/
  172.  
  173. TidyHomeFile(path,name,statbuf)
  174.  
  175. char *path;
  176. char *name;
  177. struct stat *statbuf;
  178.  
  179.   /* Tidy a file if it's past its sell-by date in kB, and if
  180.      it is greater than the specified size. Don't need an OR,
  181.      since size age can just be set to zero.                 */
  182.  
  183. { struct Tidy *tp;
  184.   struct TidyPattern *tlp;
  185.   short savetravlinks, savekilloldlinks;
  186.  
  187. for (tp = VTIDY; tp != NULL; tp=tp->next)
  188.    {
  189.    if (tp->tidylist == NULL)  /* used to eliminate non-home searches */
  190.       {
  191.       continue;
  192.       }
  193.  
  194.    for (tlp = tp->tidylist; tlp != NULL; tlp=tlp->next)
  195.       {
  196.       if (IsExcluded(tlp->classes))
  197.      {
  198.      continue;
  199.      }
  200.  
  201.       savetravlinks = TRAVLINKS;
  202.       savekilloldlinks = KILLOLDLINKS;
  203.  
  204.       ResetOutputRoute(tlp->log,tlp->inform);
  205.       
  206.       if (tlp->travlinks == 'T')
  207.          {
  208.          TRAVLINKS = true;
  209.          }
  210.       else if (tlp->travlinks == 'F')
  211.          {
  212.          TRAVLINKS = false;
  213.      }
  214.       else if (tlp->travlinks == 'K')
  215.          {
  216.          KILLOLDLINKS = true;
  217.          }
  218.  
  219.       TRAVLINKS = savetravlinks;
  220.       
  221.       if (WildMatch(tlp->pattern,name) && CheckHomeSubDir(path,tp->path,tp->recurse))
  222.          {
  223.          DoTidyFile(path,name,tlp,statbuf,CF_USELOGFILE);
  224.      }
  225.       
  226.       ResetOutputRoute('d','d');
  227.       }
  228.    }
  229.  
  230. TRAVLINKS = savetravlinks;
  231. KILLOLDLINKS = savekilloldlinks;
  232. }
  233.  
  234.  
  235. /*********************************************************************/
  236.  
  237. RecursiveTidySpecialArea(name,tp,maxrecurse)
  238.  
  239. char *name;
  240. struct Tidy *tp;
  241. int maxrecurse;
  242.  
  243. { struct stat statbuf,topstatbuf;
  244.   DIR *dirh;
  245.   struct dirent *dirp;
  246.   char pcwd[bufsize];
  247.   int is_dir,level,nostat=false;
  248.  
  249. bzero(&statbuf,sizeof(statbuf));
  250.   
  251. if (maxrecurse == -1)
  252.    {
  253.    Debug2("MAXRECURSE ran out, quitting at %s\n",name);
  254.    return;
  255.    }
  256.  
  257. if (IgnoreFile(name,"",NULL))
  258.    {
  259.    Debug2("cfengine: Ignoring directory %s\n",name);
  260.    return;
  261.    }
  262.  
  263. if (strlen(name) == 0)     /* Check for root dir */
  264.    {
  265.    name = (char *) malloc(2);
  266.    name[0] = '/';
  267.    name[1] = '\0';
  268.    }
  269.  
  270. if (maxrecurse == tp->recurse)
  271.    {
  272.    if (lstat(name,&topstatbuf) == -1)
  273.       {
  274.       if (DEBUG || D2 || VERBOSE)
  275.      {
  276.      sprintf(OUTPUT,"Can't stat %s\n",name);
  277.      CfLog(cferror,OUTPUT,"");
  278.      
  279.      if (readlink(name,VBUFF,bufsize) != -1)
  280.         {
  281.         sprintf(OUTPUT,"File is link to -> %s\n",VBUFF);
  282.         CfLog(cferror,OUTPUT,"");
  283.         }
  284.          }
  285.       return;
  286.       }
  287.    }
  288.  
  289. if ((dirh = opendir(name)) == NULL)
  290.    {
  291.    sprintf(OUTPUT,"Can't open directory [%s]\n",name);
  292.    CfLog(cferror,OUTPUT,"opendir");
  293.    return;
  294.    }
  295.  
  296. Debug("Tidy: opening dir %s\n",name);
  297.  
  298. for (dirp = readdir(dirh); dirp != NULL; dirp = readdir(dirh))
  299.    {
  300.    if (!SensibleFile(dirp->d_name,name,NULL))
  301.       {
  302.       continue;
  303.       }
  304.  
  305.    if (IgnoreFile(name,dirp->d_name,NULL))
  306.       {
  307.       continue;
  308.       }
  309.  
  310.    strcpy(pcwd,name);                                   /* Assemble pathname */
  311.    AddSlash(pcwd);
  312.  
  313.    if (BufferOverflow(pcwd,dirp->d_name))
  314.       {
  315.       return;
  316.       }
  317.  
  318.    strcat(pcwd,dirp->d_name);
  319.  
  320.    if (stat(pcwd,&statbuf) == -1)
  321.       {
  322.       nostat=true;
  323.       }
  324.  
  325.    if (S_ISDIR(statbuf.st_mode))
  326.       {
  327.       is_dir =  true;
  328.       }
  329.    else
  330.       {
  331.       is_dir = false;
  332.       }
  333.    
  334.    if (!TRAVLINKS || nostat)   /* Don't try to travlinks where we can't stat destination - just remove them */
  335.       {
  336.       if (lstat(pcwd,&statbuf) == -1)
  337.          {
  338.          if (DEBUG || D2 || VERBOSE)
  339.             {
  340.             sprintf(OUTPUT,"Can't stat %s\n",pcwd);
  341.         CfLog(cferror,OUTPUT,"lstat");
  342.             if (readlink(pcwd,VBUFF,bufsize) != -1)
  343.                {
  344.                sprintf(OUTPUT,"File is link to -> %s\n",VBUFF);
  345.            CfLog(cferror,OUTPUT,"");
  346.                }
  347.             }
  348.          continue;
  349.          }
  350.       }
  351.  
  352.    level = tp->recurse - maxrecurse;
  353.  
  354.    if (S_ISDIR(statbuf.st_mode))              /* note lstat above! */
  355.       {
  356.       if (IsMountedFileSystem(&statbuf,pcwd,1))
  357.          {
  358.          continue;
  359.          }
  360.       else
  361.          {
  362.          RecursiveTidySpecialArea(pcwd,tp,maxrecurse-1);
  363.          }
  364.  
  365.       TidyParticularFile(pcwd,dirp->d_name,tp,&statbuf,is_dir,level);
  366.       }
  367.    else
  368.       {
  369.       TidyParticularFile(pcwd,dirp->d_name,tp,&statbuf,is_dir,level);
  370.       }
  371.    }
  372.  
  373. closedir(dirh);
  374.  
  375. if (maxrecurse == tp->recurse)
  376.    {
  377.    Debug("Checking tidy topmost directory %s\n",name);
  378.  
  379.    TidyParticularFile(name,ReadLastNode(name),tp,&topstatbuf,true,tp->recurse);
  380.    }
  381. }
  382.  
  383. /*********************************************************************/
  384.  
  385. TidyParticularFile(path,name,tp,statbuf,is_dir,level)
  386.  
  387. char *path, *name;
  388. struct Tidy *tp;
  389. struct stat *statbuf;
  390. int level,is_dir;
  391.  
  392. { struct TidyPattern *tlp;
  393.  
  394. Debug2("TidyParticularFile(%s,%s)\n",path,name);
  395.  
  396. if (tp->tidylist == NULL)
  397.    {
  398.    return;
  399.    }
  400.  
  401. for (tlp = tp->tidylist; tlp != NULL; tlp=tlp->next)
  402.    {
  403.    ResetOutputRoute(tlp->log,tlp->inform);
  404.  
  405.    if (S_ISLNK(statbuf->st_mode) && is_dir && (tlp->dirlinks == 'k') && (tlp->rmdirs == 'f'))  /* Keep links to directories */
  406.       {
  407.       ResetOutputRoute('d','d');
  408.       continue;
  409.       }
  410.  
  411.    if (is_dir && tlp->rmdirs == 'f')               /* not allowed to rmdir */
  412.       {
  413.       ResetOutputRoute('d','d');
  414.       continue;
  415.       }
  416.  
  417.    if ((level == tp->recurse) && tlp->rmdirs == 's') /* rmdir subdirs only */
  418.       {
  419.       ResetOutputRoute('d','d');
  420.       continue;
  421.       }
  422.    
  423.    if (level > tlp->recurse && tlp->recurse != INFINITERECURSE)
  424.       {
  425.       Debug2("[PATTERN %s RECURSE ENDED at %d(%d) BEFORE MAXVAL %d]\n",tlp->pattern,
  426.         level,tlp->recurse,tp->recurse);
  427.       ResetOutputRoute('d','d');
  428.       continue;
  429.       }
  430.    
  431.    if (IsExcluded(tlp->classes))
  432.       {
  433.       ResetOutputRoute('d','d');
  434.       continue;
  435.       }
  436.    
  437.    if (! WildMatch(tlp->pattern,name))
  438.       {
  439.       ResetOutputRoute('d','d');
  440.       continue;
  441.       }
  442.  
  443.    if (S_ISLNK(statbuf->st_mode) && is_dir && (tlp->dirlinks == 't'))
  444.       {
  445.       Debug("Link to directory, dirlinks= says delete these\n");
  446.       }
  447.    else if (is_dir && !EmptyDir(path))
  448.       {
  449.       sprintf(OUTPUT,"Non-empty directory %s, skipping..\n",path);
  450.       CfLog(cfinform,OUTPUT,"");
  451.       ResetOutputRoute('d','d');
  452.       continue;
  453.       }
  454.    
  455.    Debug2("Matched %s to %s in %s\n",name,tlp->pattern,path);
  456.    DoTidyFile(path,name,tlp,statbuf,CF_NOLOGFILE);
  457.    ResetOutputRoute('d','d');
  458.    }
  459. }
  460.  
  461. /*********************************************************************/
  462. /* Level 2                                                           */
  463. /*********************************************************************/
  464.  
  465. DoTidyFile(path,name,tlp,statbuf,logging_this)
  466.  
  467. char *path, *name;
  468. struct TidyPattern *tlp;
  469. struct stat *statbuf;
  470. short logging_this;
  471.  
  472. { time_t nowticks, fileticks;
  473.   int size_match = false, age_match = false;
  474.  
  475. Debug2("DoTidyFile(%s,%s)\n",path,name);
  476.  
  477. nowticks = time((time_t *)NULL);             /* cmp time in days */
  478.  
  479. switch (tlp->searchtype)
  480.    {
  481.    case 'a': fileticks = statbuf->st_atime;
  482.              break;
  483.    case 'm': fileticks = statbuf->st_mtime;
  484.          break;
  485.    case 'c': fileticks = statbuf->st_ctime;
  486.          break;
  487.    default:  printf("cfengine: Internal error in DoTidyFile()\n");
  488.              break;
  489.    }
  490.  
  491. if (nowticks-fileticks < 0)                  /* shouldn't happen */
  492.    {
  493.    sprintf(OUTPUT,"ALERT: atime for %s is in the future. Check system clock!\n",path);
  494.    CfLog(cfinform,OUTPUT,"");
  495.    return;
  496.    }
  497.  
  498. if (tlp->size == CF_EMPTYFILE)
  499.    {
  500.    if (statbuf->st_size == 0)
  501.       {
  502.       size_match = true;
  503.       }
  504.    else
  505.       {
  506.       size_match = false;
  507.       }
  508.    }
  509. else
  510.    {
  511.    size_match = (tlp->size <= statbuf->st_size);
  512.    }
  513.  
  514. age_match = tlp->age*ticksperday <= (nowticks-fileticks);
  515.  
  516. if (age_match && size_match)
  517.    {
  518.    if (logging_this)
  519.       {
  520.       fprintf(VLOGFP,"cf: rm %s\n",path);
  521.       }
  522.  
  523.    if (! DONTDO)
  524.       {
  525.       if (S_ISDIR(statbuf->st_mode))
  526.      {
  527.      if (rmdir(path) == -1)
  528.         {
  529.         CfLog(cferror,"","unlink");
  530.         }
  531.      else
  532.         {
  533.         AddMultipleClasses(tlp->defines);
  534.         }
  535.      }
  536.       else
  537.      {
  538.          if (unlink(path) == -1)
  539.         {
  540.         sprintf(OUTPUT,"Couldn't unlink %s tidying\n",path);
  541.             CfLog(cfverbose,OUTPUT,"unlink");
  542.         }
  543.      else
  544.         {
  545.         AddMultipleClasses(tlp->defines);
  546.         }
  547.      }
  548.  
  549.       sprintf(OUTPUT,"Deleting %s\n",path);
  550.       CfLog(cfinform,OUTPUT,"");
  551.       sprintf(OUTPUT,"Size=%d bytes, %c-age=%d days\n",
  552.         statbuf->st_size,tlp->searchtype,(nowticks-fileticks)/ticksperday);
  553.       CfLog(cfverbose,OUTPUT,"");
  554.       }
  555.    else
  556.       {
  557.       printf("%s: want to remove %s\n",VPREFIX,path);
  558.       }
  559.    }
  560. else
  561.    {
  562.    Debug2("(No age match)\n");
  563.    }
  564. }
  565.  
  566.  
  567. /*********************************************************************/
  568.  
  569. DeleteTidyList(list)
  570.  
  571. struct TidyPattern *list;
  572.  
  573. {
  574. if (list != NULL)
  575.    {
  576.    DeleteTidyList(list->next);
  577.    list->next = NULL;
  578.  
  579.    if (list->classes != NULL)
  580.       {
  581.       free (list->classes);
  582.       }
  583.  
  584.    free((char *)list);
  585.    }
  586. }
  587.  
  588.  
  589.  
  590.  
  591.  
  592.  
  593.  
  594.